// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_
#define UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_

#include "build/build_config.h"

#include <stddef.h>

#include <list>
#include <set>
#include <vector>

#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/timer/timer.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_delegate.h"
#include "ui/views/widget/widget_observer.h"

namespace base {
class MessagePumpDispatcher;
}
namespace gfx {
class Screen;
}
namespace ui {
class OSExchangeData;
class ScopedEventDispatcher;
}
namespace views {

class MenuButton;
class MenuHostRootView;
class MenuItemView;
class MenuMessageLoop;
class MouseEvent;
class SubmenuView;
class View;

#if defined(USE_AURA)
class MenuKeyEventHandler;
#endif

namespace internal {
    class MenuControllerDelegate;
    class MenuRunnerImpl;
}

namespace test {
    class MenuControllerTest;
}

// MenuController -------------------------------------------------------------

// MenuController is used internally by the various menu classes to manage
// showing, selecting and drag/drop for menus. All relevant events are
// forwarded to the MenuController from SubmenuView and MenuHost.
class VIEWS_EXPORT MenuController : public WidgetObserver {
public:
    // Enumeration of how the menu should exit.
    enum ExitType {
        // Don't exit.
        EXIT_NONE,

        // All menus, including nested, should be exited.
        EXIT_ALL,

        // Only the outermost menu should be exited.
        EXIT_OUTERMOST,

        // This is set if the menu is being closed as the result of one of the menus
        // being destroyed.
        EXIT_DESTROYED
    };

    // If a menu is currently active, this returns the controller for it.
    static MenuController* GetActiveInstance();

    // Runs the menu at the specified location. If the menu was configured to
    // block, the selected item is returned. If the menu does not block this
    // returns NULL immediately.
    MenuItemView* Run(Widget* parent,
        MenuButton* button,
        MenuItemView* root,
        const gfx::Rect& bounds,
        MenuAnchorPosition position,
        bool context_menu,
        bool is_nested_drag,
        int* event_flags);

    // Whether or not Run blocks.
    bool IsBlockingRun() const { return blocking_run_; }

    bool in_nested_run() const { return !menu_stack_.empty(); }

    // Whether or not drag operation is in progress.
    bool drag_in_progress() const { return drag_in_progress_; }

    // Whether the MenuController initiated the drag in progress. False if there
    // is no drag in progress.
    bool did_initiate_drag() const { return did_initiate_drag_; }

    // Returns the owner of child windows.
    // WARNING: this may be NULL.
    Widget* owner() { return owner_; }

    // Get the anchor position wich is used to show this menu.
    MenuAnchorPosition GetAnchorPosition() { return state_.anchor; }

    // Cancels the current Run. See ExitType for a description of what happens
    // with the various parameters.
    void Cancel(ExitType type);

    // An alternative to Cancel(EXIT_ALL) that can be used with a OneShotTimer.
    void CancelAll() { Cancel(EXIT_ALL); }

    // When is_nested_run() this will add a delegate to the stack. The most recent
    // delegate will be notified. It will be removed upon the exiting of the
    // nested menu. Ownership is not taken.
    void AddNestedDelegate(internal::MenuControllerDelegate* delegate);

    // Sets whether the subsequent call to Run is asynchronous. When nesting calls
    // to Run, if a new MenuControllerDelegate has been nested, the previous
    // asynchronous state will be reapplied once nesting has ended.
    void SetAsyncRun(bool is_async);

    // Returns the current exit type. This returns a value other than EXIT_NONE if
    // the menu is being canceled.
    ExitType exit_type() const { return exit_type_; }

    // Returns the time from the event which closed the menu - or 0.
    base::TimeDelta closing_event_time() const { return closing_event_time_; }

    void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }

    // Various events, forwarded from the submenu.
    //
    // NOTE: the coordinates of the events are in that of the
    // MenuScrollViewContainer.
    bool OnMousePressed(SubmenuView* source, const ui::MouseEvent& event);
    bool OnMouseDragged(SubmenuView* source, const ui::MouseEvent& event);
    void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event);
    void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event);
    void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event);
    bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event);
    void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event);
    void OnTouchEvent(SubmenuView* source, ui::TouchEvent* event);
    View* GetTooltipHandlerForPoint(SubmenuView* source, const gfx::Point& point);
    void ViewHierarchyChanged(SubmenuView* source,
        const View::ViewHierarchyChangedDetails& details);

    bool GetDropFormats(SubmenuView* source,
        int* formats,
        std::set<ui::Clipboard::FormatType>* format_types);
    bool AreDropTypesRequired(SubmenuView* source);
    bool CanDrop(SubmenuView* source, const ui::OSExchangeData& data);
    void OnDragEntered(SubmenuView* source, const ui::DropTargetEvent& event);
    int OnDragUpdated(SubmenuView* source, const ui::DropTargetEvent& event);
    void OnDragExited(SubmenuView* source);
    int OnPerformDrop(SubmenuView* source, const ui::DropTargetEvent& event);

    // Invoked from the scroll buttons of the MenuScrollViewContainer.
    void OnDragEnteredScrollButton(SubmenuView* source, bool is_up);
    void OnDragExitedScrollButton(SubmenuView* source);

    // Called by the Widget when a drag is about to start on a child view. This
    // could be initiated by one of our MenuItemViews, or could be through another
    // child View.
    void OnDragWillStart();

    // Called by the Widget when the drag has completed. |should_close|
    // corresponds to whether or not the menu should close.
    void OnDragComplete(bool should_close);

    // Called while dispatching messages to intercept key events.
    // If |character| is other than 0, it is handled as a mnemonic.
    // Otherwise, |key_code| is handled as a menu navigation command.
    // Returns ui::POST_DISPATCH_NONE if the event was swallowed by the menu.
    ui::PostDispatchAction OnWillDispatchKeyEvent(base::char16 character,
        ui::KeyboardCode key_code);

    // Update the submenu's selection based on the current mouse location
    void UpdateSubmenuSelection(SubmenuView* source);

    // WidgetObserver overrides:
    void OnWidgetDestroying(Widget* widget) override;

    // Only used for testing.
    bool IsCancelAllTimerRunningForTest();

    // Only used for testing.
    static void TurnOffMenuSelectionHoldForTest();

private:
    friend class internal::MenuRunnerImpl;
    friend class test::MenuControllerTest;
    friend class MenuKeyEventHandler;
    friend class MenuHostRootView;
    friend class MenuItemView;
    friend class SubmenuView;

    class MenuScrollTask;

    struct SelectByCharDetails;

    // Values supplied to SetSelection.
    enum SetSelectionTypes {
        SELECTION_DEFAULT = 0,

        // If set submenus are opened immediately, otherwise submenus are only
        // openned after a timer fires.
        SELECTION_UPDATE_IMMEDIATELY = 1 << 0,

        // If set and the menu_item has a submenu, the submenu is shown.
        SELECTION_OPEN_SUBMENU = 1 << 1,

        // SetSelection is being invoked as the result exiting or cancelling the
        // menu. This is used for debugging.
        SELECTION_EXIT = 1 << 2,
    };

    // Direction for IncrementSelection and FindInitialSelectableMenuItem.
    enum SelectionIncrementDirectionType {
        // Navigate the menu up.
        INCREMENT_SELECTION_UP,

        // Navigate the menu down.
        INCREMENT_SELECTION_DOWN,
    };

    // Tracks selection information.
    struct State {
        State();
        ~State();

        // The selected menu item.
        MenuItemView* item;

        // If item has a submenu this indicates if the submenu is showing.
        bool submenu_open;

        // Bounds passed to the run menu. Used for positioning the first menu.
        gfx::Rect initial_bounds;

        // Position of the initial menu.
        MenuAnchorPosition anchor;

        // The direction child menus have opened in.
        std::list<bool> open_leading;

        // Bounds for the monitor we're showing on.
        gfx::Rect monitor_bounds;

        // Is the current menu a context menu.
        bool context_menu;
    };

    // Used by GetMenuPart to indicate the menu part at a particular location.
    struct MenuPart {
        // Type of part.
        enum Type {
            NONE,
            MENU_ITEM,
            SCROLL_UP,
            SCROLL_DOWN
        };

        MenuPart()
            : type(NONE)
            , menu(NULL)
            , parent(NULL)
            , submenu(NULL)
        {
        }

        // Convenience for testing type == SCROLL_DOWN or type == SCROLL_UP.
        bool is_scroll() const { return type == SCROLL_DOWN || type == SCROLL_UP; }

        // Type of part.
        Type type;

        // If type is MENU_ITEM, this is the menu item the mouse is over, otherwise
        // this is NULL.
        // NOTE: if type is MENU_ITEM and the mouse is not over a valid menu item
        //       but is over a menu (for example, the mouse is over a separator or
        //       empty menu), this is NULL and parent is the menu the mouse was
        //       clicked on.
        MenuItemView* menu;

        // If type is MENU_ITEM but the mouse is not over a menu item this is the
        // parent of the menu item the user clicked on. Otherwise this is NULL.
        MenuItemView* parent;

        // This is the submenu the mouse is over.
        SubmenuView* submenu;
    };

    // Sets the selection to |menu_item|. A value of NULL unselects
    // everything. |types| is a bitmask of |SetSelectionTypes|.
    //
    // Internally this updates pending_state_ immediatley. state_ is only updated
    // immediately if SELECTION_UPDATE_IMMEDIATELY is set. If
    // SELECTION_UPDATE_IMMEDIATELY is not set CommitPendingSelection is invoked
    // to show/hide submenus and update state_.
    void SetSelection(MenuItemView* menu_item, int types);

    void SetSelectionOnPointerDown(SubmenuView* source,
        const ui::LocatedEvent* event);
    void StartDrag(SubmenuView* source, const gfx::Point& location);

    // Key processing.
    void OnKeyDown(ui::KeyboardCode key_code);

    // Creates a MenuController. If |blocking| is true a nested message loop is
    // started in |Run|.
    MenuController(bool blocking,
        internal::MenuControllerDelegate* delegate);

    ~MenuController() override;

    // Runs the platform specific bits of the message loop. If |nested_menu| is
    // true we're being asked to run a menu from within a menu (eg a context
    // menu).
    void RunMessageLoop(bool nested_menu);

    // Invokes AcceleratorPressed() on the hot tracked view if there is one.
    // Returns true if AcceleratorPressed() was invoked.
    bool SendAcceleratorToHotTrackedView();

    void UpdateInitialLocation(const gfx::Rect& bounds,
        MenuAnchorPosition position,
        bool context_menu);

    // Invoked when the user accepts the selected item. This is only used
    // when blocking. This schedules the loop to quit.
    void Accept(MenuItemView* item, int event_flags);

    bool ShowSiblingMenu(SubmenuView* source, const gfx::Point& mouse_location);

    // Shows a context menu for |menu_item| as a result of an event if
    // appropriate, using the given |screen_location|. This is invoked on long
    // press, releasing the right mouse button, and pressing the "app" key.
    // Returns whether a context menu was shown.
    bool ShowContextMenu(MenuItemView* menu_item,
        const gfx::Point& screen_location,
        ui::MenuSourceType source_type);

    // Closes all menus, including any menus of nested invocations of Run.
    void CloseAllNestedMenus();

    // Gets the enabled menu item at the specified location.
    // If over_any_menu is non-null it is set to indicate whether the location
    // is over any menu. It is possible for this to return NULL, but
    // over_any_menu to be true. For example, the user clicked on a separator.
    MenuItemView* GetMenuItemAt(View* menu, int x, int y);

    // If there is an empty menu item at the specified location, it is returned.
    MenuItemView* GetEmptyMenuItemAt(View* source, int x, int y);

    // Returns true if the coordinate is over the scroll buttons of the
    // SubmenuView's MenuScrollViewContainer. If true is returned, part is set to
    // indicate which scroll button the coordinate is.
    bool IsScrollButtonAt(SubmenuView* source,
        int x,
        int y,
        MenuPart::Type* part);

    // Returns the target for the mouse event. The coordinates are in terms of
    // source's scroll view container.
    MenuPart GetMenuPart(SubmenuView* source, const gfx::Point& source_loc);

    // Returns the target for mouse events. The search is done through |item| and
    // all its parents.
    MenuPart GetMenuPartByScreenCoordinateUsingMenu(MenuItemView* item,
        const gfx::Point& screen_loc);

    // Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns
    // true if the supplied SubmenuView contains the location in terms of the
    // screen. If it does, part is set appropriately and true is returned.
    bool GetMenuPartByScreenCoordinateImpl(SubmenuView* menu,
        const gfx::Point& screen_loc,
        MenuPart* part);

    // Returns the RootView of the target for the mouse event, if there is a
    // target at |source_loc|.
    MenuHostRootView* GetRootView(SubmenuView* source,
        const gfx::Point& source_loc);

    // Converts the located event from |source|'s geometry to |dst|'s geometry,
    // iff the root view of source and dst differ.
    void ConvertLocatedEventForRootView(View* source,
        View* dst,
        ui::LocatedEvent* event);

    // Returns true if the SubmenuView contains the specified location. This does
    // NOT included the scroll buttons, only the submenu view.
    bool DoesSubmenuContainLocation(SubmenuView* submenu,
        const gfx::Point& screen_loc);

    // Opens/Closes the necessary menus such that state_ matches that of
    // pending_state_. This is invoked if submenus are not opened immediately,
    // but after a delay.
    void CommitPendingSelection();

    // If item has a submenu, it is closed. This does NOT update the selection
    // in anyway.
    void CloseMenu(MenuItemView* item);

    // If item has a submenu, it is opened. This does NOT update the selection
    // in anyway.
    void OpenMenu(MenuItemView* item);

    // Implementation of OpenMenu. If |show| is true, this invokes show on the
    // menu, otherwise Reposition is invoked.
    void OpenMenuImpl(MenuItemView* item, bool show);

    // Invoked when the children of a menu change and the menu is showing.
    // This closes any submenus and resizes the submenu.
    void MenuChildrenChanged(MenuItemView* item);

    // Builds the paths of the two menu items into the two paths, and
    // sets first_diff_at to the location of the first difference between the
    // two paths.
    void BuildPathsAndCalculateDiff(MenuItemView* old_item,
        MenuItemView* new_item,
        std::vector<MenuItemView*>* old_path,
        std::vector<MenuItemView*>* new_path,
        size_t* first_diff_at);

    // Builds the path for the specified item.
    void BuildMenuItemPath(MenuItemView* item, std::vector<MenuItemView*>* path);

    // Starts/stops the timer that commits the pending state to state
    // (opens/closes submenus).
    void StartShowTimer();
    void StopShowTimer();

    // Starts/stops the timer cancel the menu. This is used during drag and
    // drop when the drop enters/exits the menu.
    void StartCancelAllTimer();
    void StopCancelAllTimer();

    // Calculates the bounds of the menu to show. is_leading is set to match the
    // direction the menu opened in.
    gfx::Rect CalculateMenuBounds(MenuItemView* item,
        bool prefer_leading,
        bool* is_leading);

    // Calculates the bubble bounds of the menu to show. is_leading is set to
    // match the direction the menu opened in.
    gfx::Rect CalculateBubbleMenuBounds(MenuItemView* item,
        bool prefer_leading,
        bool* is_leading);

    // Returns the depth of the menu.
    static int MenuDepth(MenuItemView* item);

    // Selects the next or previous (depending on |direction|) menu item.
    void IncrementSelection(SelectionIncrementDirectionType direction);

    // Returns the first (|direction| == NAVIGATE_SELECTION_DOWN) or the last
    // (|direction| == INCREMENT_SELECTION_UP) selectable child menu item of
    // |parent|. If there are no selectable items returns NULL.
    MenuItemView* FindInitialSelectableMenuItem(
        MenuItemView* parent,
        SelectionIncrementDirectionType direction);

    // Returns the next or previous selectable child menu item of |parent|
    // starting at |index| and incrementing or decrementing index by 1 depending
    // on |direction|. If there are no more selectable items NULL is returned.
    MenuItemView* FindNextSelectableMenuItem(
        MenuItemView* parent,
        int index,
        SelectionIncrementDirectionType direction);

    // If the selected item has a submenu and it isn't currently open, the
    // the selection is changed such that the menu opens immediately.
    void OpenSubmenuChangeSelectionIfCan();

    // If possible, closes the submenu.
    void CloseSubmenu();

    // Returns details about which menu items match the mnemonic |key|.
    // |match_function| is used to determine which menus match.
    SelectByCharDetails FindChildForMnemonic(
        MenuItemView* parent,
        base::char16 key,
        bool (*match_function)(MenuItemView* menu, base::char16 mnemonic));

    // Selects or accepts the appropriate menu item based on |details|.
    void AcceptOrSelect(MenuItemView* parent, const SelectByCharDetails& details);

    // Selects by mnemonic, and if that doesn't work tries the first character of
    // the title.
    void SelectByChar(base::char16 key);

    // For Windows and Aura we repost an event which dismisses the |source| menu.
    // The menu is also canceled dependent on the target of the event. The event
    // is then reprocessed to cause its result if the menu had not been present.
    // On non-aura Windows, a new mouse event is generated and posted to
    // the window (if there is one) at the location of the event. On
    // aura, the event is reposted on the RootWindow.
    void RepostEventAndCancel(SubmenuView* source, const ui::LocatedEvent* event);

    // Sets the drop target to new_item.
    void SetDropMenuItem(MenuItemView* new_item,
        MenuDelegate::DropPosition position);

    // Starts/stops scrolling as appropriate. part gives the part the mouse is
    // over.
    void UpdateScrolling(const MenuPart& part);

    // Stops scrolling.
    void StopScrolling();

    // Updates active mouse view from the location of the event and sends it
    // the appropriate events. This is used to send mouse events to child views so
    // that they react to click-drag-release as if the user clicked on the view
    // itself.
    void UpdateActiveMouseView(SubmenuView* event_source,
        const ui::MouseEvent& event,
        View* target_menu);

    // Sends a mouse release event to the current active mouse view and sets
    // it to null.
    void SendMouseReleaseToActiveView(SubmenuView* event_source,
        const ui::MouseEvent& event);

    // Sends a mouse capture lost event to the current active mouse view and sets
    // it to null.
    void SendMouseCaptureLostToActiveView();

    // Sets/gets the active mouse view. See UpdateActiveMouseView() for details.
    void SetActiveMouseView(View* view);
    View* GetActiveMouseView();

    // Sets exit type. Calling this can terminate the active nested message-loop.
    void SetExitType(ExitType type);

    // Terminates the current nested message-loop, if there is any. Returns |true|
    // if any message loop is terminated.
    bool TerminateNestedMessageLoopIfNecessary();

    // Performs the teardown of menus launched with |async_run_|. This will
    // notifiy the |delegate_|. If |exit_type_| is EXIT_ALL all nested
    // asynchronous runs will be exited.
    void ExitAsyncRun();

    // Performs the teardown of the menu launched by Run(). The selected item is
    // returned.
    MenuItemView* ExitMenuRun();

    // Handles the mouse location event on the submenu |source|.
    void HandleMouseLocation(SubmenuView* source,
        const gfx::Point& mouse_location);

    // The active instance.
    static MenuController* active_instance_;

    // If true, Run blocks. If false, Run doesn't block and this is used for
    // drag and drop. Note that the semantics for drag and drop are slightly
    // different: cancel timer is kicked off any time the drag moves outside the
    // menu, mouse events do nothing...
    bool blocking_run_;

    // If true, we're showing.
    bool showing_;

    // Indicates what to exit.
    ExitType exit_type_;

    // Whether we did a capture. We do a capture only if we're blocking and
    // the mouse was down when Run.
    bool did_capture_;

    // As the user drags the mouse around pending_state_ changes immediately.
    // When the user stops moving/dragging the mouse (or clicks the mouse)
    // pending_state_ is committed to state_, potentially resulting in
    // opening or closing submenus. This gives a slight delayed effect to
    // submenus as the user moves the mouse around. This is done so that as the
    // user moves the mouse all submenus don't immediately pop.
    State pending_state_;
    State state_;

    // If the user accepted the selection, this is the result.
    MenuItemView* result_;

    // The event flags when the user selected the menu.
    int accept_event_flags_;

    // If not empty, it means we're nested. When Run is invoked from within
    // Run, the current state (state_) is pushed onto menu_stack_. This allows
    // MenuController to restore the state when the nested run returns.
    typedef std::pair<State, linked_ptr<MenuButton::PressedLock>> NestedState;
    std::list<NestedState> menu_stack_;

    // When Run is invoked during an active Run, it may be called from a separate
    // MenuControllerDelegate. If not empty is means we are nested, and the
    // stacked delegates should be notified instead of |delegate_|.
    typedef std::pair<internal::MenuControllerDelegate*, bool> NestedDelegate;
    std::list<NestedDelegate> delegate_stack_;

    // As the mouse moves around submenus are not opened immediately. Instead
    // they open after this timer fires.
    base::OneShotTimer show_timer_;

    // Used to invoke CancelAll(). This is used during drag and drop to hide the
    // menu after the mouse moves out of the of the menu. This is necessitated by
    // the lack of an ability to detect when the drag has completed from the drop
    // side.
    base::OneShotTimer cancel_all_timer_;

    // Drop target.
    MenuItemView* drop_target_;
    MenuDelegate::DropPosition drop_position_;

    // Owner of child windows.
    // WARNING: this may be NULL.
    Widget* owner_;

    // Indicates a possible drag operation.
    bool possible_drag_;

    // True when drag operation is in progress.
    bool drag_in_progress_;

    // True when the drag operation in progress was initiated by the
    // MenuController for a child MenuItemView (as opposed to initiated separately
    // by a child View).
    bool did_initiate_drag_;

    // Location the mouse was pressed at. Used to detect d&d.
    gfx::Point press_pt_;

    // We get a slew of drag updated messages as the mouse is over us. To avoid
    // continually processing whether we can drop, we cache the coordinates.
    bool valid_drop_coordinates_;
    gfx::Point drop_pt_;
    int last_drop_operation_;

    // If true, we're in the middle of invoking ShowAt on a submenu.
    bool showing_submenu_;

    // Task for scrolling the menu. If non-null indicates a scroll is currently
    // underway.
    scoped_ptr<MenuScrollTask> scroll_task_;

    // The lock to keep the menu button pressed while a menu is visible.
    scoped_ptr<MenuButton::PressedLock> pressed_lock_;

    // ViewStorage id used to store the view mouse drag events are forwarded to.
    // See UpdateActiveMouseView() for details.
    const int active_mouse_view_id_;

    internal::MenuControllerDelegate* delegate_;

    // How deep we are in nested message loops. This should be at most 2 (when
    // showing a context menu from a menu).
    int message_loop_depth_;

    // The timestamp of the event which closed the menu - or 0 otherwise.
    base::TimeDelta closing_event_time_;

    // Time when the menu is first shown.
    base::TimeTicks menu_start_time_;

    // If a mouse press triggered this menu, this will have its location (in
    // screen coordinates). Otherwise this will be (0, 0).
    gfx::Point menu_start_mouse_press_loc_;

    // Controls behviour differences between an asynchronous run, and other types
    // of run (blocking, drag and drop).
    bool async_run_;

    // Controls behavior differences between a combobox and other types of menu
    // (like a context menu).
    bool is_combobox_;

    // Set to true if the menu item was selected by touch.
    bool item_selected_by_touch_;

    // During mouse event handling, this is the RootView to forward mouse events
    // to. We need this, because if we forward one event to it (e.g., mouse
    // pressed), subsequent events (like dragging) should also go to it, even if
    // the mouse is no longer over the view.
    MenuHostRootView* current_mouse_event_target_;

    // A mask of the EventFlags for the mouse buttons currently pressed.
    int current_mouse_pressed_state_;

    scoped_ptr<MenuMessageLoop> message_loop_;

#if defined(USE_AURA)
    scoped_ptr<MenuKeyEventHandler> key_event_handler_;
#endif

    DISALLOW_COPY_AND_ASSIGN(MenuController);
};

} // namespace views

#endif // UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_
